#include "qx_hw_spi.h"
#include "qx_hw_dma.h"
#include "spi_config.h"
#include "cpu_port.h"
#include "device.h"

/* 如果采用中断tx的模式，如果spi时钟超过1Mhz，中断触发源切换的时间将超过clk的间隔，数据通讯将中断 */
//#define SPI_MASTER_TX_INTR_MODE

enum {
#if defined(BOARD_CFG_SPIA)
    SPIA_INDEX,
#endif

#if defined(BOARD_CFG_SPIB)
    SPIB_INDEX,
#endif
};

static struct qx_spi_board_config spi_board_config[] = {
#if defined(BOARD_CFG_SPIA)
        SPIA_CONFIG,
#endif

#if defined(BOARD_CFG_SPIB)
        SPIB_CONFIG,
#endif
};

static struct qx_spi_t qx_spi_obj[sizeof(spi_board_config)/sizeof(struct qx_spi_board_config)] = {0};

static rt_err_t spi_clockgate_config(volatile struct COMBINE_REGS* spi_reg)
{
    if(spi_reg == &SpiaRegs){
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIA);
        return RT_EOK;
    }else if(spi_reg == &SpibRegs){
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIB);
        return RT_EOK;
    }else{
        return RT_ERROR;
    }
}

static rt_err_t spi_gpio_config(struct qx_spi_board_config* board)
{
    GPIO_PinMux clk_mux,mosi_mux,miso_mux,cs_mux = 0;

    if(board->instance == &SpiaRegs){
        switch(board->sck_pin){
            case 3:  clk_mux = GPIO_3_SPIA_CLK; break;
            case 9:  clk_mux = GPIO_9_SPIA_CLK; break;
            case 41: clk_mux = GPIO_41_SPIA_CLK; break;
            case 56: clk_mux = GPIO_56_SPIA_CLK; break;
            default: clk_mux = 0xffUL; break;
        }

        switch(board->mosi_pin){
            case 8: mosi_mux = GPIO_8_SPIA_SIMO; break;
            case 16: mosi_mux = GPIO_16_SPIA_SIMO; break;
            default: mosi_mux = 0xffUL; break;
        }

        switch(board->miso_pin){
            case 10: miso_mux = GPIO_10_SPIA_SOMI; break;
            case 17: miso_mux = GPIO_17_SPIA_SOMI; break;
            default: miso_mux = 0xffUL; break;
        }

        switch(board->cs_pin){
            case 0: cs_mux = 0; break;
            case 5: cs_mux = GPIO_5_SPIA_STE; break;
            case 11: cs_mux = GPIO_11_SPIA_STE; break;
            case 57: cs_mux = GPIO_57_SPIA_STE; break;
            default: cs_mux = 0xffUL; break;
        }
    }else if(board->instance == &SpibRegs){
        switch(board->sck_pin){
            case 14: clk_mux = GPIO_14_SPIB_CLK; break;
            case 26: clk_mux = GPIO_26_SPIB_CLK; break;
            case 28: clk_mux = GPIO_28_SPIB_CLK; break;
            case 32: clk_mux = GPIO_32_SPIB_CLK; break;
            case 42: clk_mux = GPIO_42_SPIB_CLK; break;
            case 58: clk_mux = GPIO_58_SPIB_CLK; break;
            default: clk_mux = 0xffUL; break;
        }

        switch(board->mosi_pin){
            case 7: mosi_mux = GPIO_7_SPIB_SIMO; break;
            case 24: mosi_mux = GPIO_24_SPIB_SIMO; break;
            case 30: mosi_mux = GPIO_30_SPIB_SIMO; break;
            case 56: mosi_mux = GPIO_56_SPIB_SIMO; break;
            default: mosi_mux = 0xffUL; break;
        }

        switch(board->miso_pin){
            case 6: miso_mux = GPIO_6_SPIB_SOMI; break;
            case 25: miso_mux = GPIO_25_SPIB_SOMI; break;
            case 31: miso_mux = GPIO_31_SPIB_SOMI; break;
            case 57: miso_mux = GPIO_57_SPIB_SOMI; break;
            default: miso_mux = 0xffUL; break;
        }

        switch(board->cs_pin){
            case  0: cs_mux = 0; break;
            case 15: cs_mux = GPIO_15_SPIB_STE; break;
            case 27: cs_mux = GPIO_27_SPIB_STE; break;
            case 33: cs_mux = GPIO_33_SPIB_STE; break;
            case 59: cs_mux = GPIO_59_SPIB_STE; break;
            default: cs_mux = 0xffUL; break;
        }

    }else{
        clk_mux = 0xffUL;
    }


    if(clk_mux == 0xffUL || mosi_mux == 0xffUL || miso_mux == 0xff || cs_mux == 0xffUL){
        return RT_ERROR;
    }else{
        GPIO_MuxConfig(board->sck_pin, clk_mux, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
        GPIO_MuxConfig(board->mosi_pin, mosi_mux, GPIO_PIN_TYPE_STD,GPIO_QUAL_ASYNC);
        GPIO_MuxConfig(board->miso_pin, miso_mux, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
        /* if use spi cs pin */
        if(!cs_mux){
            GPIO_MuxConfig(board->cs_pin, cs_mux, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
        }
    }


    return RT_EOK;
}

static rt_err_t spi_parameter_config(struct qx_spi_t* spi)
{

    volatile struct COMBINE_REGS* reg = spi->board_config->instance;

    struct rt_spi_configuration* parameter = spi->cfg;

    SPI_TransferProtocol protocol = 0;

    SPI_Mode mode = 0;

    rt_uint32_t low_speed_clk = system_get_low_speed_clk();

    if((parameter->mode & RT_SPI_CPOL) && (parameter->mode &  RT_SPI_CPHA)){
        protocol = SPI_PROT_POL1PHA1;
    }else if(parameter->mode & RT_SPI_CPOL){
        protocol = SPI_PROT_POL1PHA0;
    }else if(parameter->mode & RT_SPI_CPHA){
        protocol = SPI_PROT_POL0PHA1;
    }else{
        protocol = SPI_PROT_POL0PHA0;
    }

    if(parameter->mode & RT_SPI_SLAVE){
        mode = SPI_MODE_PERIPHERAL;
    }else{
        mode = SPI_MODE_CONTROLLER;
    }

    if(parameter->data_width < 4 || parameter->data_width > 32){
        return RT_ERROR;
    }

    SPI_setConfig((rt_uint32_t)reg,low_speed_clk,protocol,mode,parameter->max_hz,(uint16_t)(parameter->data_width-1));

    SPI_disableInterrupt((rt_uint32_t)(&reg->MASTER), SPI_INT_MASK_ALL);

    return RT_EOK;
}

rt_err_t spi_interrupt_config(struct qx_spi_board_config* board)
{
    INTERRUPT_Type intr = board->intr_type;

    if(intr < INT_SPIA_M || intr > INT_SPIB_S){
        return RT_ERROR;
    }else{
        Interrupt_enable(board->intr_type);
    }

    return RT_EOK;
}

 rt_err_t qx_spi_config(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
 {
     rt_err_t ret = RT_EOK;

     struct qx_spi_t* current_spi =  rt_container_of(device->bus, struct qx_spi_t, spi_bus);

     current_spi->cfg = configuration;

     ret = spi_clockgate_config(current_spi->board_config->instance);

     ret = spi_gpio_config(current_spi->board_config);

     ret = spi_parameter_config(current_spi);

     ret = spi_interrupt_config(current_spi->board_config);

     return ret;
 }

 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin)
 {
     RT_ASSERT(bus_name != RT_NULL);
     RT_ASSERT(device_name != RT_NULL);

     rt_err_t result;
     struct rt_spi_device *spi_device;

     /* attach the device to spi bus*/
     spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
     RT_ASSERT(spi_device != RT_NULL);

     result = rt_spi_bus_attach_device_cspin(spi_device, device_name, bus_name, cs_pin, RT_NULL);
     if (result != RT_EOK)
     {
         return RT_ERROR;
     }

     RT_ASSERT(result == RT_EOK);

     return result;
 }

 rt_uint16_t remaining_send_length = 0;
 rt_uint16_t remaining_recv_length = 0;
 rt_uint8_t* remaining_send_buf = RT_NULL;
 rt_uint8_t* remaining_recv_buf = RT_NULL;

 rt_uint32_t dma_rx_reg_addr = 0;
 rt_uint32_t dma_tx_reg_addr = 0;

 void spi_trans_recv_intr(volatile struct COMBINE_REGS* instance,rt_uint8_t* s_buf,rt_uint8_t* r_buf,rt_uint16_t length)
 {
#if defined(SPI_MASTER_TX_INTR_MODE)
     rt_uint16_t keep_clk_length = length;

     spi_clear_all_interrupt_status((rt_uint32_t)(&instance->MASTER));

     SPI_writeDataNonBlocking((rt_uint32_t)(&instance->MASTER), *s_buf);

     if(length > 1){
         remaining_send_length = --length;
         remaining_send_buf = ++s_buf;
     }

     remaining_recv_buf = r_buf;
     remaining_recv_length = length+4;

     SPI_enableInterrupt((rt_uint32_t)instance, SPI_INT_MASK_TXE);

     /* back from interrupt,keep clock signal to receive data from slave */

     SPI_enableInterrupt((rt_uint32_t)instance, SPI_INT_MASK_RXF);
     while(keep_clk_length){
         SPI_writeDataNonBlocking((rt_uint32_t)(&instance->MASTER), 0x00);
         keep_clk_length--;
     }
#else
     spi_set_master_rx_fifo_Threshold_level((rt_uint32_t)(&instance->MASTER),length-4);
     remaining_recv_buf = r_buf;
     while(length){
         SPI_writeDataNonBlocking((rt_uint32_t)instance, *s_buf);
         length--;
         s_buf++;
     }
     SPI_enableInterrupt((rt_uint32_t)(&instance->MASTER), SPI_INT_MASK_RXF);
#endif
}

rt_uint32_t g_array_trace_buffer_contents[64] = {0};

void spi_trans_intr(volatile struct COMBINE_REGS* instance,rt_uint8_t* s_buf,rt_uint16_t length)
{
#if defined(SPI_MASTER_TX_INTR_MODE)
     spi_clear_all_interrupt_status((rt_uint32_t)(&instance->MASTER));

     SPI_writeDataNonBlocking((rt_uint32_t)(&instance->MASTER), *s_buf);

     if(length > 1){
         remaining_send_length = --length;
         remaining_send_buf = ++s_buf;
     }

     SPI_enableInterrupt((rt_uint32_t)(&instance->MASTER), SPI_INT_MASK_TXE);
#else
     while(length){
         SPI_writeDataNonBlocking((rt_uint32_t)instance,*s_buf);
         s_buf++;
         if(length){
             length--;
         }
     }
#endif
}


void spi_trans_dma(struct qx_spi_board_config* board,rt_uint8_t* s_buf,rt_uint16_t length)
{
    if(dma_tx_reg_addr){
        remaining_send_length = length - (board->spi_tx_dma->blockSize+1);
        DMA_configSourceAddress(dma_tx_reg_addr,(rt_uint32_t)s_buf);
        DMA_enableInterrupt(dma_tx_reg_addr,DMA_TRANSFORM_DONE_INTR);
        DMA_enableInterruptStatus(dma_tx_reg_addr,DMA_TRANSFORM_DONE_INTR);
        DMA_initController();
        DMA_startChannel(board->tx_channel);
    }
}

rt_uint32_t keep_master_clk = 0;

void spi_recv_intr(volatile struct COMBINE_REGS* instance,rt_uint8_t* r_buf,rt_uint16_t length)
{
    rt_uint8_t fifo_level = 0;
    if(length > 16){
        fifo_level = 16;
    }else{
        fifo_level = length;
    }
    spi_set_master_rx_fifo_Threshold_level((rt_uint32_t)(&instance->MASTER),fifo_level);

    remaining_recv_buf = r_buf;
    SPI_enableInterrupt((rt_uint32_t)(&instance->MASTER), SPI_INT_MASK_RXF);
    keep_master_clk = length;
    while(keep_master_clk){
        SPI_writeDataNonBlocking((rt_uint32_t)instance, 0x00);
        if(keep_master_clk){
            keep_master_clk--;
        };
    }
}

void spi_recv_dma(struct qx_spi_board_config* board,rt_uint8_t* r_buf,rt_uint16_t length)
{
    if(dma_rx_reg_addr){
        remaining_recv_length = length - (board->spi_rx_dma->blockSize+1);
        DMA_configDestAddress(dma_rx_reg_addr,(rt_uint32_t)r_buf);
        DMA_enableInterrupt(dma_rx_reg_addr,DMA_TRANSFORM_DONE_INTR);
        DMA_enableInterruptStatus(dma_rx_reg_addr,DMA_TRANSFORM_DONE_INTR);
        DMA_initController();

        rt_uint8_t* temp_data = rt_malloc(remaining_recv_length);
        rt_memset(temp_data,0,remaining_recv_length);
        DMA_configSourceAddress(dma_tx_reg_addr,(rt_uint32_t)temp_data);
        DMA_enableInterrupt(dma_tx_reg_addr,DMA_TRANSFORM_DONE_INTR);
        DMA_enableInterruptStatus(dma_tx_reg_addr,DMA_TRANSFORM_DONE_INTR);
        DMA_startChannel(board->tx_channel);

        rt_free(temp_data);
        DMA_startChannel(board->rx_channel);
    }
}

rt_uint8_t test_master_recv = 0;

void spi_trans_recv_intr_handler(volatile struct COMBINE_REGS* instance)
{
    rt_uint32_t intr_flag = SPI_getInterruptStatus((rt_uint32_t)instance);
#if defined(SPI_MASTER_TX_INTR_MODE)
    if((intr_flag & SPI_INT_STATUS_TXEI) && (remaining_send_length))
    {
       while(remaining_send_length){
           SPI_writeDataNonBlocking((rt_uint32_t)instance, *remaining_send_buf);
           remaining_send_length--;
           remaining_send_buf++;
       }

       SPI_disableInterrupt((rt_uint32_t)(&instance->MASTER), SPI_INT_MASK_TXE);
       spi_clear_all_interrupt_status((rt_uint32_t)(&instance->MASTER));
    }
#endif
    if(intr_flag & SPI_INT_STATUS_RXFI){
        while (SPI_getRxFIFOStatus((rt_uint32_t)instance) != SPI_FIFO_RXEMPTY){
            *remaining_recv_buf = SPI_readDataNonBlocking((rt_uint32_t)instance);
            remaining_recv_buf++;
        }
        spi_clear_all_interrupt_status((rt_uint32_t)(&instance->MASTER));
     }
}

void spi_rx_dma_callback(struct qx_spi_board_config* board)
{
    rt_uint32_t intr_type = 0;

    if(dma_rx_reg_addr != 0xffUL){
        intr_type = DMA_getInterruptStatus(dma_rx_reg_addr);
    }else{
        return;
    }

    if(intr_type & DMA_TRANSFORM_DONE_INTR){
        if(!remaining_recv_length){
            DMA_stopChannel(board->rx_channel);
        }else{
            DMA_clearErrorFlag(dma_rx_reg_addr,intr_type);
            rt_uint8_t* temp_tx_data = rt_malloc(remaining_recv_length);
            rt_memset(temp_tx_data,0,remaining_recv_length);
            DMA_configSourceAddress(dma_tx_reg_addr,(rt_uint32_t)temp_tx_data);
            DMA_startChannel(board->rx_channel);
            rt_free(temp_tx_data);
            remaining_recv_length -= 8;
        }
    }
}


__interrupt void spia_m_isr(void)
{
#if defined(BOARD_CFG_SPIA)
    rt_interrupt_enter();

    spi_trans_recv_intr_handler((volatile struct COMBINE_REGS*)&SpiaRegs.MASTER);

    rt_interrupt_leave();
#endif
}

__interrupt void spib_m_isr(void)
{
#if defined(BOARD_CFG_SPIB)
    rt_interrupt_enter();

    spi_trans_recv_intr_handler((volatile struct COMBINE_REGS*)&SpibRegs.MASTER);

    rt_interrupt_leave();
#endif
}

#if defined(__CORE0__) || defined(BOARD_CFG_SPIA)
#if defined(RT_SPI_USING_DMA)
#if (SPIA_TX_DMA_CHANNEL_CFG == 1)
__interrupt void dma_ch1_isr(void)
#elif (SPIA_TX_DMA_CHANNEL_CFG == 2)
__interrupt void dma_ch2_isr(void)
#elif (SPIA_TX_DMA_CHANNEL_CFG == 3)
__interrupt void dma_ch3_isr(void)
#elif (SPIA_TX_DMA_CHANNEL_CFG == 4)
__interrupt void dma_ch4_isr(void)
#elif (SPIA_TX_DMA_CHANNEL_CFG == 5)
__interrupt void dma_ch5_isr(void)
#elif (SPIA_TX_DMA_CHANNEL_CFG == 6)
__interrupt void dma_ch6_isr(void)
#else
void spi_dma_tx_foo_channel_isr(void)
#endif
{
    if(!remaining_send_length){
        DMA_stopChannel(2);
    }else{
        remaining_send_length -= 8;
        DMA_clearErrorFlag(dma_tx_reg_addr,DMA_TRANSFORM_DONE_INTR);
        DMA_startChannel(2);
    }
}
#endif

#if defined(RT_SPI_USING_DMA)
#if (SPIA_RX_DMA_CHANNEL_CFG == 1)
__interrupt void dma_ch1_isr(void)
#elif (SPIA_RX_DMA_CHANNEL_CFG == 2)
__interrupt void dma_ch2_isr(void)
#elif (SPIA_RX_DMA_CHANNEL_CFG == 3)
__interrupt void dma_ch3_isr(void)
#elif (SPIA_RX_DMA_CHANNEL_CFG == 4)
__interrupt void dma_ch4_isr(void)
#elif (SPIA_RX_DMA_CHANNEL_CFG == 5)
__interrupt void dma_ch5_isr(void)
#elif (SPIA_RX_DMA_CHANNEL_CFG == 6)
__interrupt void dma_ch6_isr(void)
#else
void spi_dma_rx_foo_channel_isr(void)
#endif
{
    rt_interrupt_enter();

    spi_rx_dma_callback(qx_spi_obj[SPIA_INDEX].board_config);

    rt_interrupt_leave();
}
#endif
#endif

rt_ssize_t qx_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
    rt_uint32_t message_length, already_send_length;
    rt_uint16_t send_length;
    rt_uint8_t *recv_buf;
    const rt_uint8_t *send_buf;

    struct qx_spi_t* current_spi =  rt_container_of(device->bus, struct qx_spi_t, spi_bus);

    message_length = message->length;

    recv_buf = message->recv_buf;

    send_buf = message->send_buf;

    if (message->cs_take && !(device->config.mode & RT_SPI_NO_CS) && (device->cs_pin != PIN_NONE))
    {
        if (device->config.mode & RT_SPI_CS_HIGH)
        {
            rt_pin_write(device->cs_pin, PIN_HIGH);
        }
        else
        {
            rt_pin_write(device->cs_pin, PIN_LOW);
        }
    }

    while(message_length){
        send_length = message_length;
        message_length = 0;

        /* tx and rx */
        if(message->send_buf && message->recv_buf){
            spi_trans_recv_intr(current_spi->board_config->instance,(rt_uint8_t*)send_buf,(rt_uint8_t*)recv_buf,send_length);
        }
        /* tx */
        else if(message->send_buf){
            if((current_spi->spi_dma_flag & RT_DEVICE_FLAG_DMA_TX)&& (send_length >= (current_spi->board_config->spi_tx_dma->blockSize+1))){
                spi_trans_dma(current_spi->board_config,(rt_uint8_t*)send_buf,send_length);
            }else{
                spi_trans_intr(current_spi->board_config->instance,(rt_uint8_t*)send_buf,send_length);
            }
        }
        /* rx */
        else{
            if(current_spi->spi_dma_flag & RT_DEVICE_FLAG_DMA_RX){
                spi_recv_dma(current_spi->board_config,(rt_uint8_t*)recv_buf,send_length);
            }else{
                spi_recv_intr(current_spi->board_config->instance,(rt_uint8_t*)recv_buf,send_length);
            }
        }
    }

    if (message->cs_release && !(device->config.mode & RT_SPI_NO_CS) && (device->cs_pin != PIN_NONE))
    {
        if (device->config.mode & RT_SPI_CS_HIGH){
            rt_pin_write(device->cs_pin, PIN_LOW);
        }
        else{
            rt_pin_write(device->cs_pin, PIN_HIGH);
        }
    }

    return message->length;
}

const struct rt_spi_ops qx_spi_ops =
{
        .configure = qx_spi_config,
        .xfer = qx_spi_xfer,
};

rt_uint32_t dma_channel_config_set(rt_uint8_t channel)
{
    rt_uint32_t reg_base = 0;
    INTERRUPT_Type intr = 0;

    switch(channel){
        case 1: reg_base = DMA_CH1_BASE; intr = INT_DMA_CH1; break;
        case 2: reg_base = DMA_CH2_BASE; intr = INT_DMA_CH2; break;
        case 3: reg_base = DMA_CH3_BASE; intr = INT_DMA_CH3; break;
        case 4: reg_base = DMA_CH4_BASE; intr = INT_DMA_CH4; break;
        case 5: reg_base = DMA_CH5_BASE; intr = INT_DMA_CH5; break;
        case 6: reg_base = DMA_CH6_BASE; intr = INT_DMA_CH6; break;
        default: reg_base = 0xffUL; intr = 0xffUL; break;
    }

    if(reg_base != 0xffUL && intr != 0xffUL){
        Interrupt_enable(intr);
    }

    return reg_base;
}

rt_err_t qx_spi_dma_mode_config(struct qx_spi_board_config* config,rt_uint16_t dma_flag)
{
    rt_err_t rst = RT_EOK;

    /* 1.first enable clock gate */
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DMA);

    DMA_ConfigParams* dma_parameter = NULL;

    /* rx config */
    if(dma_flag & RT_DEVICE_FLAG_DMA_RX){
        dma_parameter = config->spi_rx_dma;

        if(config->instance == &SpiaRegs){
            dma_parameter->srcAddr = (rt_uint32_t)&SpiaRegs.MASTER.DATA;
            SPI_enableDMA((rt_uint32_t)&SpiaRegs.MASTER,0,1);
        }else if(config->instance == &SpibRegs){
            dma_parameter->srcAddr = (rt_uint32_t)&SpibRegs.MASTER.DATA;
            SPI_enableDMA((rt_uint32_t)&SpibRegs.MASTER,0,1);
        }
        dma_rx_reg_addr = dma_channel_config_set(config->rx_channel);
        if(dma_rx_reg_addr != 0xffUL){
            DMA_configChannel(dma_rx_reg_addr,dma_parameter);
            DMA_disableAllInterrupt(dma_rx_reg_addr);
            DMA_disableAllInterruptStatus(dma_rx_reg_addr);
        }else{
            rst = RT_ERROR;
        }
    }

    /* tx config */
    if(dma_flag & RT_DEVICE_FLAG_DMA_TX){
        dma_parameter = config->spi_tx_dma;

        if(config->instance == &SpiaRegs){
            dma_parameter->destAddr = (rt_uint32_t)&SpiaRegs.MASTER.DATA;
            SPI_enableDMA((rt_uint32_t)&SpiaRegs.MASTER,1,0);
        }else if(config->instance == &SpibRegs){
            dma_parameter->destAddr = (rt_uint32_t)&SpibRegs.MASTER.DATA;
            SPI_enableDMA((rt_uint32_t)&SpibRegs.MASTER,1,0);
        }
        dma_tx_reg_addr = dma_channel_config_set(config->tx_channel);
        if(dma_tx_reg_addr != 0xffUL){
            DMA_configChannel(dma_tx_reg_addr,dma_parameter);
            DMA_disableAllInterrupt(dma_tx_reg_addr);
            DMA_disableAllInterruptStatus(dma_tx_reg_addr);
        }else{
            rst = RT_ERROR;
        }
    }

    return rst;
}

rt_err_t rt_hw_spi_bus_init(void)
{
    rt_err_t ret = RT_EOK;

    rt_uint32_t obj_num = sizeof(qx_spi_obj)/sizeof(struct qx_spi_t);

    for(rt_uint32_t i = 0; i < obj_num; i++){

        qx_spi_obj[i].board_config = &spi_board_config[i];
#if defined(RT_SPI_USING_DMA)
#if defined(BOARD_CFG_SPIA)
        if(i == SPIA_INDEX){
#if defined(BOARD_SPIA_RX_USING_DMA)
            if(qx_spi_obj[i].spi_dma_flag & RT_DEVICE_FLAG_DMA_RX){
                static DMA_ConfigParams spi_a_dma_rx = SPIA_RX_DMA_PARAM_CFG;
                qx_spi_obj[i].board_config->spi_rx_dma = &spi_a_dma_rx;
                qx_spi_obj[i].board_config->rx_channel = SPIA_RX_DMA_CHANNEL_CFG;
            }
#endif

#if defined(BOARD_SPIA_TX_USING_DMA)
            if(qx_spi_obj[i].spi_dma_flag & RT_DEVICE_FLAG_DMA_TX){
                static DMA_ConfigParams spi_a_dma_tx = SPIA_TX_DMA_PARAM_CFG;
                qx_spi_obj[i].board_config->spi_tx_dma = &spi_a_dma_tx;
                qx_spi_obj[i].board_config->tx_channel = SPIA_TX_DMA_CHANNEL_CFG;
            }
#endif
            ret = qx_spi_dma_mode_config(qx_spi_obj[i].board_config, qx_spi_obj[i].spi_dma_flag);
        }
#endif

#if defined(BOARD_CFG_SPIB)
        if(i == SPIB_INDEX){

#if defined(BOARD_SPIB_RX_USING_DMA)
            if(qx_spi_obj[i].spi_dma_flag & RT_DEVICE_FLAG_DMA_RX){
                static DMA_ConfigParams spi_b_dma_rx = SPIB_RX_DMA_PARAM_CFG;
                qx_spi_obj[i].board_config->spi_rx_dma = &spi_b_dma_rx;
                qx_spi_obj[i].board_config->rx_channel = SPIB_RX_DMA_CHANNEL_CFG;
            }
#endif

#if defined(BOARD_SPIB_TX_USING_DMA)
            if(qx_spi_obj[i].spi_dma_flag & RT_DEVICE_FLAG_DMA_TX){
                static DMA_ConfigParams spi_b_dma_tx = SPIB_TX_DMA_PARAM_CFG;
                qx_spi_obj[i].board_config->spi_tx_dma = &spi_b_dma_tx;
                qx_spi_obj[i].board_config->tx_channel = SPIB_TX_DMA_CHANNEL_CFG;
            }
#endif
            ret = qx_spi_dma_mode_config(qx_spi_obj[i].board_config, qx_spi_obj[i].spi_dma_flag);

        }
#endif
#endif

        ret = rt_spi_bus_register(&qx_spi_obj[i].spi_bus, qx_spi_obj[i].board_config->name, &qx_spi_ops);
    }

    return ret;
}

void qx_spi_dma_mode_init(void)
{
#if defined(BOARD_CFG_SPIA)
    qx_spi_obj[SPIA_INDEX].spi_dma_flag = 0;

#if defined(BOARD_SPIA_RX_USING_DMA)
    qx_spi_obj[SPIA_INDEX].spi_dma_flag |= RT_DEVICE_FLAG_DMA_RX;
#endif

#if defined(BOARD_SPIA_TX_USING_DMA)
    qx_spi_obj[SPIA_INDEX].spi_dma_flag |= RT_DEVICE_FLAG_DMA_TX;
#endif

#endif

#if defined(BOARD_CFG_SPIB)
    qx_spi_obj[SPIB_INDEX].spi_dma_flag = 0;

#if defined(BOARD_SPIB_RX_USING_DMA)
    qx_spi_obj[SPIB_INDEX].spi_dma_flag |= RT_DEVICE_FLAG_DMA_RX;
#endif

#if defined(BOARD_SPIB_TX_USING_DMA)
    qx_spi_obj[SPIB_INDEX].spi_dma_flag |= RT_DEVICE_FLAG_DMA_TX;
#endif

#endif
}

rt_err_t rt_hw_spi_init(void)
{
    /* 1.dma info check */
    qx_spi_dma_mode_init();
    /* 2.init all configured spi device */
    return rt_hw_spi_bus_init();
}
